home *** CD-ROM | disk | FTP | other *** search
/ Aminet 28 / Aminet 28 (1998)(GTI - Schatztruhe)[!][Dec 1998].iso / Aminet / game / shoot / athrust.lha / AmigaThrust / src / thrust.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-09-05  |  28.9 KB  |  1,294 lines

  1.  
  2. /* Written by Peter Ekberg, peda@lysator.liu.se */
  3.  
  4. #ifdef HAVE_CONFIG_H
  5. # include "config.h"
  6. #endif
  7.  
  8. #ifdef HAVE_UNISTD_H
  9. # include <unistd.h>
  10. #endif
  11.  
  12. #if defined(HAVE_GETOPT_H) && defined(HAVE_GETOPT_LONG_ONLY)
  13. # include <getopt.h>
  14. #elif !defined(HAVE_GETOPT_LONG_ONLY)
  15. # include "getopt.h"
  16. #endif
  17.  
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <time.h>
  22. #include <ctype.h>
  23. #include <math.h>
  24.  
  25. #include "thrust_t.h"
  26. #include "thrust.h"
  27. #include "hiscore.h"
  28. #include "graphics.h"
  29. #include "fast_gr.h"
  30. #include "gr_drv.h"
  31. #include "font5x5.h"
  32. #include "things.h"
  33. #include "conf.h"
  34. #include "init.h"
  35. #include "level.h"
  36. #include "keyboard.h"
  37. #include "options.h"
  38.  
  39. #ifdef HAVE_SOUND
  40. # include "soundIt.h"
  41.  
  42. # define CHAN_1 0
  43. # define CHAN_2 1
  44. # define CHAN_3 2
  45. # define CHAN_4 3
  46. # define SND_BOOM   0
  47. # define SND_BOOM2  1
  48. # define SND_HARP   2
  49. # define SND_THRUST 3
  50. # define SND_ZERO   4
  51. #endif
  52.  
  53. byte *bulletmap;
  54. byte *blocks;
  55. byte *ship;
  56. byte *shieldship;
  57. byte *bana;
  58. byte *fuelmap;
  59. byte *loadmap;
  60. byte *shipstorage;
  61. byte *bulletstorage;
  62. byte *fragmentstorage;
  63. byte *fuelstorage;
  64. byte *loadstorage;
  65. byte *wirestorage;
  66.  
  67. word lenx; /* x-size of level */
  68. word leny; /* y-size of level */
  69. word lenx3, leny3;
  70.              /* Status of game. */
  71. double alpha, deltaalpha;
  72. word loaded, loadcontact, loadpointshift;
  73. int loadpoint;
  74. int countdown;
  75. word crash, shoot, repetetive;
  76. word refueling;
  77. int speedx, speedy;
  78. long absspeed, oldabs;
  79. int kdir, dir;
  80. int shipdx, shipdy;
  81. int x, y;              /* Top left corner, 8 units per pixel. */
  82. int pixx, pixy;        /* Top left corner in pixels.   */
  83. int pblockx, pblocky;  /* Top left corner in blocks (8x8 pixels). */
  84. int vx, vy;                             /* Speed of the ship. */
  85. int bildx, bildy;      /* Top left corner of backing store (in pixels). */
  86. int bblockx, bblocky;  /* Top left corner of backing store (in blocks). */
  87. int loadbx, loadby;    /* Position of the load (in blocks). */
  88. int gravity;
  89. int score;
  90. byte shield;
  91. byte colorr, colorg, colorb;
  92. int nodemo=0;
  93. int Thrust_Is_On=0;
  94. int play_sound=1;
  95. double gamma_correction=1.0;
  96. int skip_frames=0;
  97.  
  98. #define checkfork(b, a) \
  99.   case b-1: \
  100.     if(easyrider==a || easyrider==a+1) \
  101.       easyrider=a+1; \
  102.     else if(easyrider!=9) \
  103.       easyrider=-1; \
  104.     break
  105.  
  106. int
  107. insideblock(int blkx, int blky, int pblkx, int pblky,
  108.             int sx, int sy)
  109. {
  110.   return((blkx>=pblkx-sx) && (blkx<pblkx+BBILDX) &&
  111.          (blky>=pblky-sy) && (blky<pblky+BBILDY));
  112. }
  113.  
  114. int
  115. insidepixel(int x, int y, int pixx, int pixy, int sx, int sy)
  116. {
  117.   return((x>pixx-sx) && (x<pixx+PUSEX) &&
  118.          (y>pixy-sy) && (y<pixy+PUSEY));
  119. }
  120.  
  121. void
  122. updateborder(int pblkx, int pblky, int bblkx, int bblky,
  123.              int vx, int vy)
  124. {
  125.   word k;
  126.  
  127.   if(vy<=0) /* update bottom border */
  128.     for(k=0; k<BBILDX; k++)
  129.       putblock(bblkx+k, (bblky+BBILDY-1)%BBILDY, blocks+
  130.                (*(bana+(pblkx+k)%lenx+((pblky+BBILDY-1)%leny)*lenx)<<6));
  131.   else      /* update top border */
  132.     for(k=0; k<BBILDX; k++)
  133.       putblock(bblkx+k, bblky, blocks+
  134.                (*(bana+(pblkx+k)%lenx+(pblky%leny)*lenx)<<6));
  135.   if(vx>0)  /* update right border */
  136.     for(k=0; k<BBILDY; k++)
  137.       putblock(bblkx+BBILDX-1, (bblky+k)%BBILDY, blocks+
  138.                (*(bana+(pblkx+BBILDX-1)%lenx+((pblky+k)%leny)*lenx)<<6));
  139.   else      /* update left border */
  140.     for(k=0; k<BBILDY; k++)
  141.       putblock(bblkx, (bblky+k)%BBILDY, blocks+
  142.                (*(bana+pblkx%lenx+((pblky+k)%leny)*lenx)<<6));
  143. }
  144.  
  145. void
  146. pause_message(void)
  147. {
  148.   char *str[] = {
  149.     "Game paused.",
  150.     "Press 'C' to continue..." };
  151.  
  152.   chflag=1;
  153.   gcenter(80, str[0]);
  154.   gcenter(91, str[1]);
  155.   chflag=0;
  156.   displayscreen();
  157. }
  158.  
  159. void
  160. escape_message(void)
  161. {
  162.   char *str[] = {
  163.     "Are you sure you want to quit (Y/N)?" };
  164.  
  165.   chflag=1;
  166.   gcenter(85, str[0]);
  167.   chflag=0;
  168.   displayscreen();
  169. }
  170.  
  171. byte
  172. whatkeys(void)
  173. {
  174.   byte keys;
  175.  
  176. /* Use this to create a demo.
  177.  * Don't forget to uncomment the fputc statement below.
  178.  */
  179.   /*
  180.   static FILE *f=NULL;
  181.   if(f == NULL)
  182.     f=fopen("foobarfoo", "w");
  183.   */
  184.  
  185.   keys = getkeys();
  186.  
  187.   /*
  188.   fputc((keys&escape_bit)?quit_bit:keys, f);
  189.   */
  190.   return(keys);
  191. }
  192.  
  193. byte
  194. nextmove(int reset)
  195. {
  196.   static byte *p;
  197.   byte retbits=0;
  198.  
  199.   if(reset) {
  200.     keywaiting();
  201.     p=&bin_demomove[0];
  202.   }
  203.   else if(keywaiting()) {
  204.     retbits=quit_bit;
  205.     flushkeyboard();
  206.   }
  207.   else {
  208.     retbits=*(p++);
  209.     retbits&=~thrust_bit;
  210.     retbits|=*(p-!!(random()%20)) & thrust_bit;
  211.   }
  212.  
  213.   return(retbits);
  214. }
  215.  
  216. void
  217. gamestatusframe(void)
  218. {
  219.   int i, maxx;
  220.  
  221.   for(i=3; i<317; i++)
  222.     putpixel(i, 3, 0x88);
  223.   for(i=3; i<11; i++) {
  224.     putpixel(  3, i, 0x88);
  225.     putpixel(  4, i, 0x88);
  226.     putpixel(315, i, 0x88);
  227.     putpixel(316, i, 0x88);
  228.   }
  229.   for(i=3; i<11; i++) {
  230.     putpixel(    i, i+8, 0x88);
  231.     putpixel(  1+i, i+8, 0x88);
  232.     putpixel(318-i, i+8, 0x88);
  233.     putpixel(319-i, i+8, 0x88);
  234.   }
  235.   for(i=9; i<311; i++)
  236.     putpixel(i, 18, 0x88);
  237.   maxx = 80-gstrlen("FUEL")-2;
  238.   for(i=6; i<maxx; i++) {
  239.     putpixel(i, 6, 65);
  240.     putpixel(i, 8, 65);
  241.   }
  242.   maxx = 160-gstrlen("LIVES")/2-2;
  243.   for(i=82; i<maxx; i++) {
  244.     putpixel(i, 6, 65);
  245.     putpixel(i, 8, 65);
  246.   }
  247.   maxx = 280-gstrlen("SCORE")-2;
  248.   for(i=160+gstrlen("LIVES")/2+2; i<maxx; i++) {
  249.     putpixel(i, 6, 65);
  250.     putpixel(i, 8, 65);
  251.   }
  252.   for(i=282; i<313; i++) {
  253.     putpixel(i, 6, 65);
  254.     putpixel(i, 8, 65);
  255.   }
  256.   chcolor = 0x89;
  257.   printgs(80-gstrlen("FUEL"), 5, "FUEL");
  258.   gcenter(5, "LIVES");
  259.   printgs(280-gstrlen("SCORE"), 5, "SCORE");
  260.   chcolor = TEXTCOLOR;
  261. }
  262.  
  263. void
  264. gamestatus(int lives, int fuel, int score)
  265. {
  266.   static char textstr[40];
  267.  
  268.   chcolor = 0x88;
  269.   drawfuel(fuel);
  270.   sprintf(textstr, "%d", lives);
  271.   gcenter(12, textstr);
  272.   sprintf(textstr, "%d", score);
  273.   printgs(280-gstrlen(textstr), 12, textstr);
  274.   chcolor = TEXTCOLOR;
  275. }
  276.  
  277. int
  278. game(int demo)
  279. {
  280.   byte actionbits=0;
  281.   double ax, ay, aradial, acircum;
  282.   word lives, endlevel;
  283.   word dying;
  284.   word alive;
  285.   word fuel;
  286.   int l;
  287.   int level;
  288.   int round;
  289.   static char **levels[LEVELS]
  290.     = { level1, level2, level3, level4, level5, level6 };
  291.   static char textstr[40];
  292.   int localscore;
  293.   options end;
  294.   int ch;
  295.   int lastlevel;
  296.   int easyrider=0;
  297.   int restartx=0, restarty=0;
  298.   int loadedrestart=0;
  299.   restartpoint *restartxy;
  300.   int gravitymsg;
  301.   int visibilitymsg;
  302.   int teleport;
  303.  
  304.   if(demo)
  305.     nextmove(1);
  306.  
  307.   lives=3; /* 3 */
  308.   localscore=0;
  309.   score=0;
  310.   round=0; /* 0 */
  311.   level=0; /* 0 */
  312.   lastlevel=-1;
  313.   shield=0;
  314.   fuel=1000; /* 1000 */
  315.   gravitymsg=0;
  316.   visibilitymsg=0;
  317.   teleport=0;
  318.  
  319.   while(level<LEVELS && lives>0 && fuel) {
  320. #ifdef DEBUG2
  321.     printf("Newlevel: %d\n", level);
  322. #endif
  323.     endlevel = 0;
  324.     dying    = 0;
  325.     alive    = 1;
  326.     
  327.     srandom(time(NULL));
  328.     if(level!=lastlevel || !powerplant) {
  329.       if(level==0 && lastlevel>0) {
  330.         gravitymsg = 1;
  331.         if(round == 2)
  332.           visibilitymsg = 1;
  333.       }
  334.       if(!readbana(levels[level])) {
  335.         printf("Illegal definition of level %d.\n", level+1);
  336.         return(1);
  337.       }
  338.       restartx = (lenx+restartpoints[0].x-(154>>3))%lenx;
  339.       restarty = restartpoints[0].y-(82>>3)-4*(round&1);
  340.       loadedrestart = 0;
  341.       initgame(round, 1, restartx, restarty);
  342.     }
  343.     else {
  344.       loaded = loadedrestart;
  345.       initgame(round, 0, restartx, restarty);
  346.     }
  347.  
  348.     initscreen(round);
  349.     putscr(pixx%PBILDX, pixy%PBILDY, 1);
  350.     lastlevel = level;
  351.  
  352.     gamestatusframe();
  353.     gamestatus(lives, fuel, score);
  354.     sprintf(textstr, "Level %d",  level+1);
  355.     gcenter(70, textstr);
  356.     if(gravitymsg) {
  357.       gcenter(60, (round&1) ? "Reversed gravity" : "Normal gravity");
  358.       if(visibilitymsg)
  359.         gcenter(52, (round&2) ? "Invisible ground" : "Visible ground");
  360.     }
  361.     displayscreen();
  362.     syncscreen();
  363.     fade_in();
  364.     usleep(1000000UL + 2000000UL*gravitymsg);
  365.     gravitymsg=0;
  366.     syncscreen();
  367.     putscr(pixx%PBILDX, pixy%PBILDY, 1);
  368.     drawteleport(1);
  369.     displayscreen();
  370.     while(!endlevel) {
  371.       actionbits=demo ? nextmove(0) : whatkeys();
  372.  
  373.       if(actionbits&quit_bit) {
  374. #ifdef DEBUG2
  375.         printf("Endlevel: User pressed quit-key\n");
  376. #endif
  377.         endlevel=1;
  378.       }
  379.  
  380.       if(actionbits&pause_bit) {
  381. #ifdef HAVE_SOUND
  382.         if(play_sound) {
  383.           Thrust_Is_On=0;
  384.           Snd_effect(SND_ZERO, CHAN_1);
  385.         }
  386. #endif
  387.         pause_message();
  388.         singlekey();
  389.         end=NOTHING;
  390.         while(getkey());
  391.         while(end==NOTHING) {
  392.           ch=getkey();
  393.           switch(tolower(ch)) {
  394.           case 'p':
  395.             if(easyrider!=9)
  396.               easyrider=0;
  397.             break;
  398.           case 't':
  399.             checkfork('m', 0);
  400.             checkfork('b', 1);
  401.             checkfork('z', 2);
  402.             checkfork('h', 3);
  403.             checkfork('s', 4);
  404.             checkfork('p', 5);
  405.             checkfork('v', 6);
  406.             checkfork('o', 7);
  407.             checkfork('e', 8);
  408.             break;
  409.           case 'c':
  410.           case 'q':
  411.           case 27:
  412.             end=PLAY;
  413.             break;
  414.           }
  415.           usleep(50000UL);
  416.         }
  417.         if(easyrider!=9)
  418.           easyrider=0;
  419.         multiplekeys();
  420.       }
  421.       if(actionbits&escape_bit) {
  422. #ifdef HAVE_SOUND
  423.         if(play_sound) {
  424.           Thrust_Is_On=0;
  425.           Snd_effect(SND_ZERO, CHAN_1);
  426.         }
  427. #endif
  428.         escape_message();
  429.         singlekey();
  430.         end=NOTHING;
  431.         while(end==NOTHING) {
  432.           ch=getkey();
  433.           switch(tolower(ch)) {
  434.           case 'y':
  435.             end=END;
  436. #ifdef DEBUG2
  437.             printf("Endlevel: User answered yes efter ESC.\n");
  438. #endif
  439.             endlevel=1;
  440.             level=LEVELS;
  441.             break;
  442.           case 'n':
  443.             end=PLAY;
  444.             break;
  445.           }
  446.           usleep(50000UL);
  447.         }
  448.         multiplekeys();
  449.       }
  450.       if(alive && (actionbits&right_bit)) {
  451.         decr(kdir, 0, 96);
  452.         dir=kdir/3;
  453.       }
  454.       if(alive && (actionbits&left_bit)) {
  455.         incr(kdir, 96, 0);
  456.         dir=kdir/3;
  457.       }
  458.       if(alive && (actionbits&fire_bit)) {
  459.         if(!shoot) {
  460.           shoot=1;
  461.           newbullet(x+((160+shipdx)<<3)+74*cos(dir * M_PI/16),
  462.                     y+(( 88+shipdy)<<3)-74*sin(dir * M_PI/16),
  463.                     speedx/256.0+32*cos(dir * M_PI/16),
  464.                     speedy/256.0+32*sin(dir * M_PI/16),
  465.                     kdir/6, 1);
  466.         }
  467.         else if(repetetive || easyrider)
  468.           shoot=0;
  469.       }
  470.       else
  471.         shoot=0;
  472.       refueling=0;
  473.       if(alive && (actionbits&pickup_bit)) {
  474.         if(fuel>0) {
  475.           if(shield++==3) {
  476. #if !(defined(DEBUG) || defined(DEBUG2))
  477.             if(!easyrider)
  478.               fuel--;
  479. #endif
  480.             shield=1;
  481.           }
  482.         }
  483.         else
  484.           shield=0;
  485.         l=closestfuel((pixx+shipdx+160)%lenx3,
  486.                       (pixy+shipdy+88)%leny3);
  487.         if(l>=0)
  488.           if(resonablefuel((pixx+shipdx+160)%lenx3,
  489.                            (pixy+shipdy+88)%leny3, l)) {
  490. #ifndef DEBUG
  491.             if(!easyrider)
  492.               fuel+=6;
  493. #endif
  494.             refueling=1;
  495.             things[l].alive--;
  496.             if(things[l].alive==1)
  497.               things[l].score=300;
  498.           }
  499.         if(!loaded)
  500.           if(inloadcontact((pixx+shipdx+160)%lenx3,
  501.                            (pixy+shipdy+88)%leny3)) {
  502.             loadcontact=1;
  503.             *(bana+lenx*loadby+loadbx)=32;
  504.             drawload(0);
  505.           }
  506.       }
  507.       else {
  508.         shield=0;
  509.         if(alive && loadcontact) {
  510.           *(bana+lenx*loadby+loadbx)=109;
  511.           drawload(1);
  512.           loadcontact=0;
  513.         }
  514.       }
  515.       if(alive && (actionbits&thrust_bit)) {
  516.         if(fuel>0) {
  517. #ifdef HAVE_SOUND
  518.           if(play_sound)
  519.             if(Thrust_Is_On==0) {
  520.               Thrust_Is_On=1;
  521.               Snd_effect(SND_THRUST, CHAN_1);
  522.             }
  523. #endif
  524. #if !(defined(DEBUG) || defined(DEBUG2))
  525.           if(!easyrider)
  526.             fuel--;
  527. #endif
  528.           oldabs=speedx*(long)speedx+speedy*(long)speedy;
  529.  
  530.           if(loaded) { /* Ship and blob */
  531.             aradial  = cos(dir * M_PI/16 - alpha);
  532.             acircum  = sin(dir * M_PI/16 - alpha);
  533.             ax =
  534.               SPEED/2
  535.               * (aradial*cos(alpha) - acircum*sin(alpha)/(1 + REL_MASS))
  536.               / (1 + REL_MASS);
  537.             ay =
  538.               SPEED/2
  539.               * (aradial*sin(alpha) - acircum*cos(alpha)/(1 + REL_MASS))
  540.               / (1 + REL_MASS);
  541.             deltaalpha += SPEED/2 * acircum * M_PI/262144;
  542.           }
  543.           else {       /* Ship, no blob */
  544.             ax=SPEED*cos(dir * M_PI/16) / 2;
  545.             ay=SPEED*sin(dir * M_PI/16) / 2;
  546.           }
  547.  
  548.           speedx+=ax;
  549.           speedy+=ay;
  550.           absspeed=speedx*(long)speedx+speedy*(long)speedy;
  551.           if(absspeed>1000000000L && absspeed>oldabs) {
  552.             speedx-=ax;
  553.             speedy-=ay;
  554.           }
  555.         }
  556.         else {
  557. #ifdef HAVE_SOUND
  558.           if(play_sound)
  559.             if(Thrust_Is_On == 1) {
  560.               Snd_effect(SND_ZERO, CHAN_1);
  561.               Thrust_Is_On = 0;
  562.             }
  563. #endif
  564.         }
  565.       }
  566.       else {
  567. #ifdef HAVE_SOUND
  568.         if(play_sound)
  569.           if(Thrust_Is_On == 1) {
  570.             Snd_effect(SND_ZERO, CHAN_1);
  571.             Thrust_Is_On = 0;
  572.           }
  573. #endif
  574.       }
  575.       if(loaded) {
  576.         if(loadpointshift) {
  577.           speedx+=shipdx*12;
  578.           speedy+=shipdy*12;
  579.         }
  580.         alpha+=deltaalpha;
  581.         if(alpha>2*M_PI)
  582.           alpha-=2*M_PI;
  583.         if(alpha<0)
  584.           alpha+=2*M_PI;
  585.         loadpointshift=0;
  586.         if(++loadpoint>126)
  587.           loadpoint=126;
  588.         else
  589.           loadpointshift=1;
  590.         shipdx= cos(alpha)*loadpoint/5.90625;
  591.         shipdy=-sin(alpha)*loadpoint/5.90625;
  592.         if(loadpointshift) {
  593.           speedx-=shipdx*12;
  594.           speedy-=shipdy*12;
  595.         }
  596.         deltaalpha-=deltaalpha/1024;
  597.       }
  598.       else
  599.         shipdx=shipdy=0;
  600.       /* Gravity and Aerodynamics */
  601.       if(speedx>0)
  602.         speedx=speedx-(speedx>>9)-1;
  603.       else if(speedx<0)
  604.         speedx=speedx-(speedx>>9)+1;
  605.       if(alive) {
  606.         if(gravity>=0)
  607.           speedy-=(SPEED*gravity+1)>>8;
  608.         else
  609.           speedy-=(SPEED*gravity>>8)+1;
  610.         if(speedy>0)
  611.           speedy--;
  612.         else if(speedy<0)
  613.           speedy++;
  614.         /* Move the Ship */
  615.         speedx=min(speedx, 16384);
  616.         speedx=max(speedx, -16384);
  617.         speedy=min(speedy, 16384);
  618.         speedy=max(speedy, -16384);
  619.         if(speedx>=0)
  620.           vx=(speedx+1)>>8;
  621.         else
  622.           vx=(speedx>>8)+1;
  623.         if(speedy>=0)
  624.           vy=(speedy+1)>>8;
  625.         else
  626.           vy=(speedy>>8)+1;
  627.         x=(x+vx+(lenx<<6))%(lenx<<6);
  628.         y=(y-vy+(leny<<6))%(leny<<6);
  629.       }
  630.  
  631.       /* Bunkerfire */
  632.       if(!ppblip)
  633.         bunkerfirebullets();
  634.       movebullets();
  635.       movefragments();
  636.       drawfuel(fuel);
  637.  
  638.       /* Move the Power Plant blip */
  639.       ppcount=(ppcount+1)&15;
  640.       if(!ppcount && powerplant && ppblip)
  641.         ppblip--;
  642.  
  643.       if(!powerplant) {
  644.         countdown--;
  645.         if(countdown<0) {
  646. #ifndef DEBUG
  647.           if(alive && !easyrider) {
  648.             dying=1;
  649. #ifdef DEBUG2
  650.             printf("Dying: Power Plant countdown.\n");
  651. #endif
  652.           }
  653. #endif
  654.         }
  655.         else {
  656.           chflag=1;
  657.           sprintf(textstr, "%d  ", (countdown+99)/100);
  658.           printgs(105, 12, textstr);
  659.           printgs(205, 12, textstr);
  660.           chflag=0;
  661.         }
  662.       }
  663.  
  664.       /* Precalculate some values */
  665.       pixx=x>>3;
  666.       pixy=y>>3;
  667.       bildx=(pixx+PBILDX-4)%PBILDX+4;
  668.       bildy=pixy%PBILDY;
  669.       pblockx=pixx>>3;
  670.       pblocky=pixy>>3;
  671.       bblockx=bildx>>3;
  672.       bblocky=bildy>>3;
  673.  
  674.       if(pblocky>leny-3) {
  675.         endlevel=1;
  676. #ifdef DEBUG2
  677.         printf("Endlevel: Finished level.\n");
  678. #endif
  679.         teleport=1;
  680.         y=0;
  681.         pixy=0;
  682.         pblocky=0;
  683.       }
  684.  
  685.       /* Check if at a restart barrier. If so, update the restart point. */
  686.       restartxy=atbarrier((pblockx+((154+shipdx)>>3))%lenx,
  687.                           pblocky+((82+shipdy)>>3));
  688.       if(restartxy) {
  689.         restartx=(lenx+restartxy->x-(154>>3))%lenx;
  690.         restarty=restartxy->y-(82>>3);
  691.         loadedrestart=loaded;
  692.       }
  693.  
  694.       /* Scroll the screen */
  695.       updateborder(pblockx, pblocky, bblockx, bblocky, vx, vy);
  696.       
  697.       drawpowerplantblip();
  698.       drawbullets();
  699.       if(alive)
  700.         crash=drawshuttle();
  701.       drawfragments();
  702.       if(alive && refueling)
  703.         drawfuellines();
  704.       /* Check if end of life. */
  705. #ifndef DEBUG
  706.       if(!easyrider)
  707.         if(alive && crash) {
  708.           lives--;
  709.           dying=1;
  710. #ifdef DEBUG2
  711.           printf("Dying: Crashing.\n");
  712. #endif
  713.         }
  714. #endif
  715.       /* Wait for the screen retrace and then dump the graphics to it. */
  716.       /* Screendump */
  717.  
  718.       syncscreen();
  719.       putscr(bildx, bildy, 0);
  720.       displayscreen();
  721.  
  722.       /* Remove moveable objects from screen in reverse order. */
  723.       if(alive && refueling)
  724.         undrawfuellines();
  725.       undrawfragments();
  726.       if(alive)
  727.         undrawshuttle();
  728.       undrawbullets();
  729.         
  730.       /* Remove objects */
  731.       if(!easyrider)
  732.         localscore+=killdyingthings();
  733.       else
  734.         killdyingthings();
  735.       if(dying) {
  736.         alive=0;
  737.         dying=0;
  738. #ifdef HAVE_SOUND
  739.         if(play_sound) {
  740.           Snd_effect(SND_ZERO, CHAN_1);
  741.           Thrust_Is_On=0;
  742.           Snd_effect(SND_BOOM2, CHAN_2);
  743.         }
  744. #endif
  745.         explodeship();
  746.       }
  747.       if(!alive && !livefragments()) {
  748. #ifdef HAVE_SOUND
  749.         if(play_sound) {
  750.           Snd_effect(SND_ZERO, CHAN_1);
  751.           Thrust_Is_On=0;
  752.         }
  753. #endif
  754.         endlevel=1;
  755. #ifdef DEBUG2
  756.         printf("Endlevel: Shit crashed.\n");
  757. #endif
  758.       }
  759.       animatesliders();
  760.       if(localscore>score) {
  761.         chflag=1;
  762.         if(localscore/10000 > score/10000)
  763.           lives++;
  764.         score=localscore;
  765.         gamestatus(lives, fuel, score);
  766.         chflag=0;       
  767.       }
  768.     }
  769.     if(teleport) {
  770. #ifdef HAVE_SOUND
  771.       if(play_sound)
  772.         Snd_effect(SND_ZERO, CHAN_1);
  773. #endif
  774.       bin_colors[65*3+0]=GAMMA(colorr);
  775.       bin_colors[65*3+1]=GAMMA(colorg);
  776.       bin_colors[65*3+2]=GAMMA(colorb);
  777.       fadepalette(0, 255, bin_colors, 64, 1);
  778.       drawteleport(0);
  779.     }
  780.  
  781.     if(!(actionbits&(quit_bit|escape_bit)))
  782.       usleep(1000000UL);
  783.     fade_out();
  784.  
  785.     if(!demo && !(actionbits&(quit_bit|escape_bit))) {
  786.       if(teleport || !powerplant) {
  787.         chflag=1;
  788.         gamestatusframe();
  789.         gamestatus(lives, fuel, score);
  790.  
  791.         if(!powerplant) {
  792.           sprintf(textstr, "Planet destroyed");
  793.           gcenter(61, textstr);
  794.         }
  795.  
  796.         if(teleport && loaded)
  797.           sprintf(textstr, "Mission %d complete", level+1);
  798.         else if(powerplant)
  799.           sprintf(textstr, "Mission incomplete");
  800.         else
  801.           sprintf(textstr, "Misson  %d  failed", level+1);
  802.         gcenter(73-6*(teleport && loaded && powerplant), textstr);
  803.  
  804.         if((teleport && loaded) || !powerplant) {
  805.           if(teleport && loaded)
  806.             sprintf(textstr, "Bonus %d", 4000+400*level-2000*powerplant);
  807.           else
  808.             sprintf(textstr, "No bonus");
  809.           gcenter(85-6*(!!powerplant), textstr);
  810.         }
  811.  
  812.         displayscreen();
  813.         fade_in();
  814.         usleep(2000000UL);
  815.         if(!easyrider && teleport && loaded)
  816.           localscore+=4000+400*level-2000*powerplant;
  817.         if((teleport && loaded) || !powerplant) {
  818.           if(++level==LEVELS) {
  819.             level=0;
  820.             round=(round+1)%4;
  821.           }
  822.         }
  823.         if(localscore/10000 > score/10000)
  824.           lives++;
  825.         score=localscore;
  826.         gamestatus(lives, fuel, score);
  827.         chflag=0;
  828.         displayscreen();
  829.         usleep(2000000UL);
  830.         fade_out();
  831.       }
  832.     }
  833.     teleport=0;
  834.  
  835.     if(demo)
  836.       level=LEVELS;
  837.   }
  838.  
  839.   if(!demo) {
  840.     chflag=1;
  841.     gamestatusframe();
  842.     gamestatus(lives, fuel, score);
  843.  
  844.     gcenter(73, "Game Over");
  845.  
  846.     displayscreen();
  847.     fade_in();
  848.     usleep(2000000UL);
  849.     fade_out();
  850.   }
  851.  
  852.   return(0);
  853. }
  854.  
  855. void
  856. pressanykey(void)
  857. {
  858.   singlekey();
  859.  
  860.   do 
  861.     usleep(50000UL);
  862.   while(!getkey());
  863.  
  864.   multiplekeys();
  865. }
  866.  
  867. int
  868. instructions(void)
  869. {
  870.   int i;
  871.   static char *keys[] = {
  872.     "Esc", "P", "C" };
  873.   static char *func[] = {
  874.     "Turn left", "Turn right", "Thrust", "Fire",
  875.     "Pick up & Shield", "Quit Game (Q=Esc)", "Pause", "Continue" };
  876.   static char *story[] = {
  877.     "The resistance is about to launch a major offensive against",
  878.     "the Intergalactic Empire. In preparation for this, they have",
  879.     "captured several battle-grade starships, but they lack the",
  880.     "essential power sources for these formidable craft; Klystron",
  881.     "Pods. You have been commissioned by resistance to steal these",
  882.     "pods from the Empire's storage planets. Each planet is",
  883.     "defended by a battery of 'Limpet' guns, powered by a nuclear",
  884.     "power plant. By firing shots at the power plant, the guns can",
  885.     "be temporarily disabled; the more shots fired at the nuclear",
  886.     "reactor, the longer the guns will take to recharge.",
  887.     "BUT BEWARE!! If you fire too many shots at the reactor, it",
  888.     "will become critical, giving you just ten seconds to clear",
  889.     "the plantet before it is destroyed. If you have not already",
  890.     "retrieved the pod stored at the planet, then you will have",
  891.     "failed the mission. If you have retrieved the pod, and you",
  892.     "manage to send the reactor into its critical phase, and",
  893.     "leave the planet safely, you will receive a hefty bonus.",
  894.     NULL };
  895.   static char *score[] = {
  896.     "Destroying a limpet gun:",
  897.     "Destroying a fuel cell:",
  898.     "Picking up a fuel cell:",
  899.     "Bonus for destroying planet:",
  900.     "",
  901.     "A spare ship is allocated for every:"
  902.   };
  903.   static char *scores[] = {
  904.     "750",
  905.     "150",
  906.     "300",
  907.     "2000 + Mission Bonus",
  908.     "",
  909.     "10000"
  910.   };
  911.  
  912.   chcolor = HIGHLIGHT;
  913.   gcenter(20, "THE SILLY STORY!");
  914.   chcolor = TEXTCOLOR;
  915.   for(i=0; story[i]; i++)
  916.     gcenter(35 + i*8, story[i]);
  917.  
  918.   gcenter(180, "Press any key for the next page.");
  919.  
  920.   fade_in();
  921.   pressanykey();
  922.   fade_out();
  923.  
  924.   chcolor = HIGHLIGHT;
  925.   gcenter(40, "SCORING");
  926.   chcolor = TEXTCOLOR;
  927.   for(i=0; i<6; i++) {
  928.     chcolor = TEXTCOLOR;
  929.     printgs(200-gstrlen(score[i]), 65 + 8*i, score[i]);
  930.     chcolor = HIGHLIGHT;
  931.     printgs(205, 65 + 8*i, scores[i]);
  932.   }
  933.  
  934.   chcolor = TEXTCOLOR;
  935.   gcenter(130, "Press any key for the next page.");
  936.  
  937.   fade_in();
  938.   pressanykey();
  939.   fade_out();
  940.  
  941.   gcenter(50, "The following keys are used:");
  942.   for(i=0; i<8; i++) {
  943.     chcolor = HIGHLIGHT;
  944.     if(i<5)
  945.       printgs(140-gstrlen(keystring(scancode[i])),
  946.               63+i*8+2*(i>4),
  947.               keystring(scancode[i]));
  948.     else
  949.       printgs(140-gstrlen(keys[i-5]), 63+i*8+2*(i>4), keys[i-5]);
  950.     chcolor = TEXTCOLOR;
  951.     printgs(145, 63+i*8+2*(i>4), func[i]);
  952.   }
  953.   gcenter(150, "Press any key for the main menu.");
  954.  
  955.   fade_in();
  956.   pressanykey();
  957.   fade_out();
  958.  
  959.   return(0);
  960. }
  961.  
  962. int
  963. about(void)
  964. {
  965.   int i;
  966.   static char *str[] = {
  967.     "Thrust version " VERSION,
  968.     "",
  969.     "Written by",
  970.     "",
  971.     "Peter Ekberg",
  972.     "peda@lysator.liu.se",
  973.     "",
  974. #ifdef AMIGA
  975.     "Amiga Ports (M68k, PowerPC) by",
  976.     "Frank Wille",
  977.     "frank@phoenix.owl.de",
  978.     "",
  979. #endif
  980.     "Thanks to the authors",
  981.     "of the original",
  982.     "for the C64.",
  983.     NULL
  984.   };
  985.  
  986.   for(i=0; str[i]; i++) {
  987. #ifdef AMIGA
  988.     if (i==5 || i==9)
  989. #else
  990.     if(i==5)
  991. #endif
  992.       chcolor = HIGHLIGHT;
  993.     else
  994.       chcolor = TEXTCOLOR;
  995. #ifdef AMIGA
  996.     gcenter(10+9*i, str[i]);
  997. #else
  998.     gcenter(40+9*i, str[i]);
  999. #endif
  1000.   }
  1001.   gcenter(145, "Press any key for the main menu.");
  1002.  
  1003.   fade_in();
  1004.   pressanykey();
  1005.   fade_out();
  1006.  
  1007.   return(0);
  1008. }
  1009.  
  1010. char *
  1011. enterhighscorename(void)
  1012. {
  1013.   static char name[40];
  1014.   char str[40];
  1015.   
  1016.   strcpy(name, standardname());
  1017.   sprintf(str, "You managed %d points!", score);
  1018.   gcenter(64, str);
  1019.   gcenter(75, "You made it into the highscore list!");
  1020.   gcenter(86, "Enter your name:");
  1021.   printgs(130, 97, name);
  1022.   fade_in();
  1023.  
  1024.   singlekey();
  1025.  
  1026.   if(readgs(130, 97, name, 39, 80, 0)==-1)
  1027.     strcpy(name, standardname());
  1028.  
  1029.   multiplekeys();
  1030.  
  1031.   fade_out();
  1032.  
  1033.   return(name);
  1034. }
  1035.  
  1036. int
  1037. showhighscores(void)
  1038. {
  1039.   char str[100];
  1040.   byte tmp=chcolor;
  1041.   int i;
  1042.   int scorew, namew;
  1043.   int len;
  1044.  
  1045.   gcenter(50, "The current highscores are");
  1046.  
  1047.   scorew=namew=0;
  1048.   for(i=0; i<HIGHSCORES; i++) {
  1049.     sprintf(str, "%d", highscorelist[i].score);
  1050.     len=gstrlen(str);
  1051.     if(len>scorew)
  1052.       scorew=len;
  1053.     len=gstrlen(highscorelist[i].name);
  1054.     if(len>namew)
  1055.       namew=len;
  1056.   }
  1057.  
  1058.   for(i=0; i<HIGHSCORES; i++) {
  1059.     sprintf(str, "%d", highscorelist[i].score);
  1060.     chcolor = SCORETEXT;
  1061.     printgs(155+(scorew-namew)/2-gstrlen(str), 70+11*i, str);
  1062.     chcolor = SCORENAME;
  1063.     printgs(165+(scorew-namew)/2, 70+11*i, highscorelist[i].name);
  1064.   }
  1065.  
  1066.   chcolor=tmp;
  1067.   gcenter(145, "Press any key for the main menu.");
  1068.  
  1069.   fade_in();
  1070.   pressanykey();
  1071.   fade_out();
  1072.  
  1073.   return(0);
  1074. }
  1075.  
  1076. void
  1077. newhighscore(void)
  1078. {
  1079.   char *name;
  1080.  
  1081.   name = enterhighscorename();
  1082.   inserthighscore(name, score);
  1083.   writehighscores();
  1084.   showhighscores();
  1085. }
  1086.  
  1087. options
  1088. menu(void)
  1089. {
  1090.   int i;
  1091.   options end=NOTHING;
  1092.   int ch;
  1093.   static char *menuchoises[NOTHING]= { "I", "C", "H", "P", "A", "Q" };
  1094.   static char *menuoptions[NOTHING]= {
  1095.     "Instructions", "Configuration", "Highscores", 
  1096.     "Play Game", "About", "Quit" };
  1097.   int count=0;
  1098.  
  1099.   clearscr();
  1100.   putarea(title_pixels, 0, 0, title_cols, title_rows, title_cols,
  1101.           (PUSEX-title_cols)>>1, (PUSEY+24-title_rows)>>1);
  1102.   for(i=0; i<NOTHING; i++) {
  1103.     chcolor = TEXTCOLOR;
  1104.     printgs(20, 134+i*11, menuoptions[i]);
  1105.     chcolor = HIGHLIGHT;
  1106.     printgs(20, 134+i*11, menuchoises[i]);
  1107.   }
  1108.   printgs(60, 35, "GRATTIS CALLE!");
  1109.   chcolor = TEXTCOLOR;
  1110.  
  1111.   fade_in();
  1112.   singlekey();
  1113.  
  1114.   while(end==NOTHING) {
  1115.     ch=getkey();
  1116.     switch(tolower(ch)) {
  1117.     case 0:
  1118.       break;
  1119.     case 'i':
  1120.       end=INST;
  1121.       break;
  1122.     case 'p':
  1123.       end=PLAY;
  1124.       break;
  1125.     case 'h':
  1126.       end=HI;
  1127.       break;
  1128.     case 'a':
  1129.       end=ABOUT;
  1130.       break;
  1131.     case 'c':
  1132.       end=CONF;
  1133.       break;
  1134.     case 'd':
  1135.       end=DEMO;
  1136.       break;
  1137.     case 'q':
  1138.     case 27:
  1139.       end=END;
  1140.       break;
  1141.     default:
  1142.       count=0;
  1143.       break;
  1144.     }
  1145.     usleep(50000UL);
  1146.  
  1147.     if(++count==160 && end==NOTHING) {
  1148.       if(!nodemo)
  1149.         end=DEMO;
  1150.       count=0;
  1151.     }
  1152.   }
  1153.  
  1154.   multiplekeys();
  1155.   fade_out();
  1156.  
  1157.   return(end);
  1158. }
  1159.  
  1160. int
  1161. main(int argc, char **argv)
  1162. {
  1163.   int end=0;
  1164.   int optc;
  1165.  
  1166.   do {
  1167.     static struct option longopts[] = {
  1168.       OPTS,
  1169.       SVGA_OPTS,
  1170.       X_OPTS,
  1171.       { 0, 0, 0, 0 }
  1172.     };
  1173.  
  1174.     optc=getopt_long_only(argc, argv,
  1175.                           OPTC SVGA_OPTC X_OPTC, longopts, (int *)0);
  1176.     switch(optc) {
  1177.     case 's':      /* --svgamode */
  1178.     case 'm':      /* --noshm */
  1179.     case 'X':      /* -display */
  1180.     case 'g':      /* -geometry */
  1181.     case '2':      /* --double */
  1182.       break;
  1183.     case 'e':      /* --nosoundeffects */
  1184.       play_sound=0;
  1185.       break;
  1186.     case 'd':      /* --nodemo */
  1187.       nodemo=1;
  1188.       break;
  1189.     case 'c':      /* --gamma */
  1190.       {
  1191.         char *end;
  1192.         double tmp;
  1193.  
  1194.         if(*optarg) {
  1195.           tmp = strtod(optarg, &end);
  1196.           if(*end || tmp==HUGE_VAL || tmp<=0.0)
  1197.             tmp = 0.0;
  1198.         }
  1199.         else
  1200.           tmp = 0.0;
  1201.  
  1202.         if(tmp == 0.0)
  1203.           printf("Illegal gamma correction value: \"%s\"\n", optarg);
  1204.         else
  1205.           gamma_correction = tmp;
  1206.       }
  1207.       break;
  1208.     case 'j':      /* --step */
  1209.       skip_frames = 1;
  1210.       break;
  1211.     case 'h':      /* --help */
  1212.       printf("Thrust: version " VERSION " -- the Game\n");
  1213.       printf("Using %s to drive the graphics and\n"
  1214.              "      %s to drive the keyboard.\n\n",
  1215.              graphicsname(),
  1216.              keyname());
  1217.       printf("usage: thrust [OPTION]...\n\n"
  1218.              "  -v, --version\n"
  1219.              "  -h, --help\n"
  1220.              "  -d, --nodemo           Do not run the demo.\n"
  1221.              "  -e, --nosoundeffects   Do not play sound effects.\n"
  1222.              "  -c, --gamma=Value      Gamma correction of colors.\n"
  1223.              "  -j, --step             Only draw every third frame (faster).\n");
  1224.       if(!strcmp(graphicsname(), "SVGA")) {
  1225.         printf("  -s, --svgamode=MODE    The format of MODE is G<width>x<height>x<colors>\n");
  1226.       }
  1227.       if(!strcmp(graphicsname(), "X11")) {
  1228.         printf("  -m, --noshm            Do not use shared memory (slower).\n"
  1229.                "  -2, --double           Double the size of the window (slower).\n"
  1230.                "  -display display-name  See the X man page for details.\n"
  1231.                "  -geometry geom-spec    See the X man page for details.\n");
  1232.       }
  1233.       printf("\n");
  1234.       exit(1);
  1235.     case 'v':      /* --version */
  1236.       printf("Thrust: version " VERSION "\n");
  1237.       exit(0);
  1238.     case EOF:
  1239.       if(optind == argc)
  1240.         break;
  1241.     default:
  1242.       fprintf(stderr, "Thrust: bad usage (see 'thrust -h')\n");
  1243.       exit(1);
  1244.     }
  1245.   } while(optc != EOF);
  1246.  
  1247.   graphics_preinit();
  1248.   inithardware(argc, argv);
  1249.  
  1250.   if(!initmem()) {
  1251.     restorehardware();
  1252.     return(1);
  1253.   }
  1254.   inithighscorelist();
  1255.   initkeys();
  1256.  
  1257.   usleep(1000000L); /* phx - replaces sleep(1) */
  1258.  
  1259.   while(!end) {
  1260.     switch(menu()) {
  1261.     case INST:
  1262.       instructions();
  1263.       break;
  1264.     case PLAY:
  1265.       if(!(end=game(0)))
  1266.         if(ahighscore(score))
  1267.           newhighscore();
  1268.       break;
  1269.     case HI:
  1270.       showhighscores();
  1271.       break;
  1272.     case ABOUT:
  1273.       about();
  1274.       break;
  1275.     case CONF:
  1276.       conf();
  1277.       break;
  1278.     case DEMO:
  1279.       game(1);
  1280.       break;
  1281.     case END:
  1282.       end=1;
  1283.       break;
  1284.     default:
  1285.       break;
  1286.     }
  1287.   }
  1288.  
  1289.   restoremem();
  1290.   restorehardware();
  1291.   
  1292.   return(0);
  1293. }
  1294.